/**
 * @file localStorage/sessionStorage相关
 * @author its-wild(https://gitee.com/its-wild)
 * @date 2021/07/13
 */
import { App } from 'vue'

export interface IStorageOptions {
  namespace: string
}

export declare interface Storage {
  type: string;
  /**
   * 设置 storage
   * @param name 要存的名称
   * @param value 要存的值
   * @param expire 过期时间，单位：秒
   */
  set: (name: string, value: any, expire: number) => void;
  /**
   * 获取 storage 的值
   * @param name 要取的名称
   * @returns any
   */
  get: (name: string) => any;
  /**
   * 移除指定的 storage
   * @param name 要移除的名称
   */
  remove: (name: string) => void;
  /**
   * 移除所以带命名空间（ namespace ） storage
   */
  clear: () => void;
}

// 存储的默认配置项
let storageOptions = {
  namespace: 'its__' // 存储的时候的key的前缀
}

/**
 * 初始化配置项
 * @param options 存储的配置项
 * @returns void
 */
const init = (options?: IStorageOptions): void => {
  if (!options) return
  storageOptions = {
    ...options
  }
}
/**
 * 清除所以带命名空间（ namespace ）的缓存
 * @param type local/session
 */
const clear = (type: string) => {
  const storage = (window as any)[type + 'Storage']
  const removedKeys = []

  for (let i = 0; i < storage.length; i++) {
    const key = storage.key(i)
    const regexp = new RegExp(`^${storageOptions.namespace}.+`, 'i')

    if (regexp.test(key) === false) {
      continue
    }

    removedKeys.push(key)
  }

  for (const key in removedKeys) {
    storage.removeItem(removedKeys[key])
  }
}
/**
 * 移除缓存
 * @param type local/session
 * @param name 要移除的名称
 */
const remove = (type: string, name: string) => {
  const storage = (window as any)[type + 'Storage']
  storage.removeItem(storageOptions.namespace + name)
}
/**
 * 设置缓存
 * @param type local/session
 * @param name 要存的名称
 * @param value 要存的值
 * @param expire 过期时间，单位：秒
 */
const set = (type: string, name: string, value: unknown, expire?: number) => {
  const stringifyValue = JSON.stringify({
    value,
    expire: expire ? new Date().getTime() + expire : null
  })
  const storage = (window as any)[type + 'Storage']
  storage.setItem(storageOptions.namespace + name, stringifyValue)
}
/**
 * 获取缓存
 * @param type local/session
 * @param name 要取的名称
 * @returns unknown
 */
const get = (type: string, name: string): unknown => {
  const res = null
  const storage = (window as any)[type + 'Storage']
  const item = storage.getItem(storageOptions.namespace + name);

  if (item !== null) {
    try {
      const data = JSON.parse(item);

      if (data.expire === null) {
        return data.value
      }

      if (data.expire >= new Date().getTime()) {
        return data.value
      }

      remove(type, name)
    } catch (err) {
      return res
    }
  }
  return res
}

const baseOpt = {
  type: '',
  /**
   * 设置 storage
   * @param name 要存的名称
   * @param value 要存的值
   * @param expire 过期时间，单位：秒
   */
  set(name: string, value: any, expire: number) {
    set(this.type, name, value, expire)
  },
  /**
   * 获取 storage 的值
   * @param name 要取的名称
   * @returns unknown
   */
  get(name: string): unknown {
    return get(this.type, name)
  },
  /**
   * 移除指定的 storage
   * @param name 要移除的名称
   */
  remove(name: string) {
    remove(this.type, name)
  },
  /**
   * 移除所以带命名空间（ namespace ） storage
   */
  clear() {
    clear(this.type)
  }
}

export const local = {
  ...baseOpt,
  type: 'local'
}

export const session = {
  ...baseOpt,
  type: 'session'
}

export default {
  init,
  install(app: App, options: IStorageOptions): void {
    init(options)
    app.config.globalProperties.$local = local
    app.config.globalProperties.$session = session
  },
  local,
  session
}
